package com.cheng.im.gateway.session;

import com.alibaba.fastjson2.JSONObject;
import com.cheng.im.common.bean.UserDTO;
import com.cheng.im.common.bean.msg.ProtoMsg;
import com.cheng.im.common.bean.msg.ProtoMsgV1;
import com.cheng.im.common.constants.ServerConstants;
import com.cheng.im.gateway.session.manager.SessionManger;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.util.UUID;

/**
 * @author Cheng
 */
@Data
@Slf4j
public class LocalSession implements ServerSession {

    private String sessionId;

    private Channel channel;

    private boolean isLogin = false;

    private UserDTO user;

    public static final AttributeKey<LocalSession> SESSION_KEY = AttributeKey.valueOf("SESSION_KEY");


    public LocalSession(Channel channel) {
        this.channel = channel;
        this.sessionId = buildNewSessionId();
    }

    /**
     * 生成一个uuid
     * @return
     */
    private static String buildNewSessionId() {
        String uuid = UUID.randomUUID().toString();
        return uuid.replaceAll("-", "");
    }

    /**
     * 用户下线，通知其他用户
     */
    public synchronized void close() {
        ChannelFuture future = channel.close();
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                if (!future.isSuccess()) {
                    log.error("CHANNEL_CLOSED error ");
                }
                // todo: 下线通知
            }
        });
    }

    /**
     * 绑定localSession到channel
     * @return
     */
    public LocalSession bind() {
        log.info(" LocalSession 绑定会话 " + channel.remoteAddress());
        channel.attr(LocalSession.SESSION_KEY).set(this);
        channel.attr(ServerConstants.CHANNEL_NAME).set(JSONObject.toJSONString(user));
        isLogin = true;
        return this;
    }

    public LocalSession unbind() {
        isLogin = false;
        SessionManger.inst().removeSession(getSessionId(), this.getUser().getAppId());
        this.close();
        return this;
    }

    public static LocalSession getSession(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        return channel.attr(LocalSession.SESSION_KEY).get();
    }

    /**
     * 发送消息给客户端，然后关闭channel
     * @param response 发送的消息
     */
    public void writeAndClose(ProtoMsgV1.Message response) {
        channel.writeAndFlush(response);
        close();
    }

    /**
     * 发送消息给客户端
     * @param pkg
     */
    @Override
    public synchronized void writeAndFlush(Object pkg) {

        if (channel.isWritable()) //低水位
        {
            channel.writeAndFlush(pkg);
        } else {   //高水位时
            log.debug("通道很忙，消息被暂存了");
            // 写入消息暂存的分布式存储，如果mongo
            // todo: 等channel空闲之后，再写出去
        }
    }

    @Override
    public boolean isValid() {
        return getUser() != null ? true : false;
    }

    @Override
    public String getUserId() {
        return user.getUserId();
    }
}
